#ifndef MATRIX_H
#define MATRIX_H

namespace Cvekas {

/// 4x4 %Matrix
class Matrix : public D3DXMATRIX
{
public:
	Matrix();
	Matrix( const float* f );
	Matrix( const D3DXFLOAT16* f );
	Matrix( const D3DMATRIX& m );
	Matrix( const D3DXMATRIX& m );
	Matrix( float _11, float _12, float _13, float _14,
            float _21, float _22, float _23, float _24,
            float _31, float _32, float _33, float _34,
            float _41, float _42, float _43, float _44 );

	operator D3DXMATRIX&();
    operator const D3DXMATRIX&() const;

	void transpose()
	{
		Matrix m;
		D3DXMatrixTranspose(&m, this);
		*this = m;
	}

	static Matrix translate(const Vector3& translate)
	{
		Matrix m;
		D3DXMatrixTranslation(&m, translate.x, translate.y, translate.z);
		return m;
	}

	static Matrix rotate(const Vector3& rotate)
	{
		Matrix m;
		D3DXMatrixRotationYawPitchRoll(&m, rotate.y, rotate.x, rotate.z);
		return m;
	}

	static Matrix scale(const Vector3& scale)
	{
		Matrix m;
		D3DXMatrixScaling(&m, scale.x, scale.y, scale.z);
		return m;
	}

	static Matrix lookAt(const Vector3& pos, const Vector3& at, const Vector3& up)
	{
		Matrix m;
		D3DXMatrixLookAtLH(&m, &pos, &at, &up);
		return m;
	}

	static Matrix perspective(float fov, float aspect_ratio, float z_near, float z_far)
	{
		assert(z_near < z_far);
		Matrix m;
		D3DXMatrixPerspectiveFovLH(&m, fov, aspect_ratio, z_near, z_far);
		return m;
	}

	static Matrix identity()
	{
		Matrix m;
		D3DXMatrixIdentity(&m);
		return m;
	}
};

inline Matrix::Matrix() : D3DXMATRIX() { };
inline Matrix::Matrix( const float *f ) : D3DXMATRIX(f) { };
inline Matrix::Matrix( const D3DXFLOAT16 *f ) : D3DXMATRIX(f) { };
inline Matrix::Matrix( const D3DXMATRIX& v ) : D3DXMATRIX(v) { };
inline Matrix::Matrix( float _11, float _12, float _13, float _14,
            float _21, float _22, float _23, float _24,
            float _31, float _32, float _33, float _34,
            float _41, float _42, float _43, float _44 )
            : D3DXMATRIX(_11,_12,_13,_14,_21,_22,_23,_24,_31,_32,_33,_34,_41,_42,_43,_44) { }

inline Matrix::operator D3DXMATRIX&() { return *this; }
inline Matrix::operator const D3DXMATRIX&() const { return *this; }

} // namespace

#endif